package com.bear.newsset.widget;

import android.content.Context;
import android.graphics.Color;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.AttributeSet;
import android.view.View;

import androidx.annotation.IntRange;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.LinearLayoutManager;

import com.bear.newsset.adapter.BaseXRecyclerViewAdapter;
import com.bear.newsset.adapter.NewsListAdapter;
import com.bear.newsset.dao.entity.NewsLikeSqlEntity;
import com.bear.newsset.dao.sql.NewsStatusSQL;
import com.bear.newsset.entity.NewsListEntity;
import com.bear.newsset.entity.NewsParamEntity;
import com.bear.newsset.entity.ResultSubItemEntity;
import com.bear.newsset.mvp.model.NewsModel;
import com.bear.newsset.ui.activity.NSApplication;
import com.bear.newsset.util.LogUtils;
import com.bear.newsset.util.Utils;
import com.bear.newsset.widget.item.BaseNewsItemView;
import com.bumptech.glide.Glide;
import com.jcodecraeer.xrecyclerview.ProgressStyle;
import com.jcodecraeer.xrecyclerview.XRecyclerView;
import com.ybear.ybmvp.util.MVPUtil;

import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;

/**
 * 新闻列表
 * 通过设置参数来访问后台获取新闻数据，适配器只会生成一次，其他时刻均为修改List数据集
 * 在获取参数（刷新数据、追加数据）时会隐藏组件（防止下拉刷新异常），直到数据到达后才显示
 * 获取数据分为两拨，一波是初始化时的设置适配器，另一波为追加数据。
 */
public class NewsListRecyclerView extends XRecyclerView implements
        XRecyclerView.LoadingListener,
        BaseXRecyclerViewAdapter.OnItemClickListener<NewsListEntity> {

    /**
     * 刷新数据类型
     */
    public enum  REFRESH {
        DEFAULT,    //不做任何处理
        HEAD,       //下拉刷新
        FOOT        //上拉加载
    }

    /**
     * 刷新新闻数据状态接口
     */
    public interface OnRefreshStatusListener {
        void onLoading();                            //加载中
        void onResponse(NewsParamEntity paramEntity, List<NewsListEntity> list);  //加载成功
        void onFailure();                            //加载失败
    }

    /**
     * 回调结果
     */
    public interface CallbackResult { void result(boolean result); }

    private Context mContext;
    private NewsModel newsModel;
    private NewsParamEntity mParamEntity;
    private ThisHandler mThisHandler;
    private NewsListAdapter mAdapter;
    private NewsStatusSQL mStatusSQL;
    private REFRESH currentRefresh;
    private OnRefreshStatusListener mOnRefreshStatusListener;
    private NewsListAdapter.OnClickInsideMoreBtnListener mOnClickInsideMoreBtnListener;

    private List<NewsListEntity> mDataList;
    private boolean isDataFirst;        //是否是第一次获取数据

    public NewsListRecyclerView(@NonNull Context context) {
        super(context);
        init(context);
    }

    /**
     * 以控件的形式使用
     * @param context       上下文
     * @param attrs         attrs
     */
    public NewsListRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    /**
     * 初始化
     * @param mContext      上下文
     */
    private void init(final Context mContext) {
        this.mContext = mContext;
        mThisHandler = new ThisHandler( this );
        newsModel = MVPUtil.newClass( NewsModel.class );
        currentRefresh = REFRESH.DEFAULT;
        isDataFirst = false;

        initView();
        initData();
        initListener();
    }

    /**
     * 初始化视图
     */
    private void initView() {
        //默认隐藏
        setVisibility(View.INVISIBLE);
        //设置背景色为白色
        setBackgroundColor(Color.WHITE);
        //设置为线性布局
        setLayoutManager(new LinearLayoutManager(mContext));
        //设置上拉加载的样式
        setLoadingMoreProgressStyle(ProgressStyle.BallBeat);
        //设置上拉加载的提示文本
        setFootViewText("正在加载", "上拉加载");
    }

    /**
     * 初始化数据
     */
    private void initData() {
        mStatusSQL = NewsStatusSQL.getInstance();
        mDataList = new ArrayList<>();
        mAdapter = new NewsListAdapter(Glide.with( this ), mDataList);

        setAdapter( mAdapter );
        //数据加载监听器
        setLoadingListener( this );
    }

    /**
     * 初始化监听器
     */
    private void initListener() {
        //长按弹出更多上的按钮点击事件监听器
        mAdapter.setOnClickInsideMoreBtnListener((v, type, isSelect, itemData, position) -> {
            //保存喜欢的相关状态
            saveLikeStatus(itemData, type);
            if( mOnClickInsideMoreBtnListener != null ) {
                mOnClickInsideMoreBtnListener.onClick(v, type, isSelect, itemData, position);
            }
        });

        mAdapter.setOnItemClickListener( this );

        //长按弹出更多事件监听器
        mAdapter.setOnLongClickMoreListener((v, itemData) -> {
            String newsId = itemData.getItemData().getId();
            NewsLikeSqlEntity e = getLikeStatus( newsId );
            //初始化按钮的状态
            v.initMoreInsideBtnStatus(e.getIsGiveLike(), e.getIsCollect(), e.getIsShare());
        });
    }

    /**
     * 设置点击更多里边的按钮事件监听器
     * @param listener      监听器
     */
    public void setOnClickInsideMoreBtnListener(
            @NonNull NewsListAdapter.OnClickInsideMoreBtnListener listener) {
        mOnClickInsideMoreBtnListener = listener;
    }

    /**
     * 获取新闻喜欢的状态
     * @param newsId    新闻id
     * @return          喜欢的状态
     */
    @NonNull
    public NewsLikeSqlEntity getLikeStatus(String newsId) {
        return mStatusSQL.queryNewsLikeSqlForNewsId( newsId );
    }

    /**
     * 保存喜欢的相关状态
     * @param itemData      新闻数据
     * @param type          喜欢的类型
     */
    private void saveLikeStatus(NewsListEntity itemData, BaseNewsItemView.CLICK_TYPE type) {
        String newsId = itemData.getItemData().getId();
        NewsLikeSqlEntity like = getLikeStatus( newsId );
        //当前账号
        String account = ((NSApplication) (mContext.getApplicationContext()))
                .getAccountEntity()
                .getAccount();

        like.setAccount( account );
        //设置新闻id
        like.setNewsId( newsId );
        //设置相应的操作
        switch ( type ) {
            case GIVE_LIKE:     //喜欢按钮
                like.setIsGiveLike( !like.getIsGiveLike() );
                break;
            case COLLECT:       //收藏按钮
                like.setIsCollect( !like.getIsCollect() );
                break;
            case SHARE:         //分享按钮
                like.setIsShare( true );
                break;
        }
        //保存设置的结果
        mStatusSQL.insertNewsLikeSql( like );
    }

    /**
     * 下拉刷新监听
     */
    @Override
    public void onRefresh() {
        refreshData( REFRESH.HEAD );
    }

    /**
     * 上拉加载监听
     */
    @Override
    public void onLoadMore() {
        refreshData( REFRESH.FOOT );
    }

    /**
     * 刷新数据
     * @param r     刷新类型 {@link REFRESH#HEAD}, {@link REFRESH#FOOT}
     */
    private void refreshData(REFRESH r) {
        NewsParamEntity footParam = new NewsParamEntity()
                .setParam( mParamEntity )
                .setPageToken( "-1" );
        int what = r == REFRESH.HEAD ? 101 : r == REFRESH.FOOT ? 102 : 0;
        if( what == 0 ) return;
        //设置新闻参数
        setNewsParam(r, r == REFRESH.FOOT ? footParam : mParamEntity);
        //请求新闻数据
        requestNewsData(result -> {
            mThisHandler.sendEmptyMessage( what );     //刷新完毕
        });
    }

    /**
     * Item点击事件
     * @param view          Item
     * @param itemData      Item数据
     * @param position      当前位置
     */
    @Override
    public void onItemClick(View view, NewsListEntity itemData, int position) {
        //跳转到新闻内容页面
        Utils.startContentActivity(mContext, itemData);
    }

    /**
     * 通知数据发生改变
     * @param dataList  改变的数据列表
     */
    private void notifyDataChange(List<NewsListEntity> dataList, boolean isRemove) {
        if( dataList == null || ( dataList.size() == 0 && mDataList.size() > 0 ) ) return;
        //清空原数据列表
        if( isRemove ) mDataList.clear();
        //加入新数据
        mDataList.addAll( dataList );
        //刷新数据
        mThisHandler.sendEmptyMessage( 100 );
    }

    /**
     * 设置刷新状态
     * @param status    -1：失败，0：加载中，1：成功
     */
    private void setRefreshStatus(@IntRange(from = -1, to = 1) int status) {
        if( mOnRefreshStatusListener == null ) return;
        switch ( status ) {
            case 0:     //加载中
                LogUtils.d("setRefreshStatus", "加载中：" + status);
                mOnRefreshStatusListener.onLoading();
                break;
            case 1:     //加载成功
                LogUtils.d("setRefreshStatus", "加载成功：" + status);
                mOnRefreshStatusListener.onResponse( mParamEntity, mDataList );
                break;
            default:    //加载失败
                LogUtils.d("setRefreshStatus", "加载失败：" + status);
                mOnRefreshStatusListener.onFailure();
                break;
        }
    }

    /**
     * 处理请求的新闻数据
     * 回调刷新状态通过size判断，这不是很明智，应该通过返回code决定。
     * @param list                  新闻列表
     * @param e                     完整请求类
     * @param mCallbackResult       回调
     */
    private void doRequestNewsData(@NonNull List<NewsListEntity> list,
                                   @Nullable ResultSubItemEntity e,
                                   @Nullable CallbackResult mCallbackResult) {
        LogUtils.d("doRequestNewsData", "ListSize:" + list.size() + " " + e);
        //返回数据的主标签Id
        long callMainLableId = e == null ? -1 : e.getMainLableId();
        //返回的数据必须是当前所需要的数据，否则就跳过
        if( callMainLableId != -1 && mParamEntity.getMainLableId() != callMainLableId ) return;
        //设置新闻数据
        setNewsDataList(mParamEntity.getMainLableId(), currentRefresh, list);
        //设置刷新状态为 成功 or 失败
        setRefreshStatus( list.size() > 0 ? 1 : -1 );
        //回调结果
        if( mCallbackResult != null ) mCallbackResult.result( true );
    }

    /**
     * 请求新闻数据
     * @param mCallbackResult   回调请求结果
     */
    public void requestNewsData(@Nullable CallbackResult mCallbackResult) {
        if( mParamEntity == null ) throw new NullPointerException("News param entity not null!");
        //默认刷新时隐藏列表
        if( currentRefresh == REFRESH.DEFAULT ) mThisHandler.sendEmptyMessage( 501 );
        //设置刷新状态为 加载中
        setRefreshStatus( 0 );
        //获取新闻列表
        newsModel.getNewsList(mParamEntity, ((listData, entity) -> {
            //处理请求的新闻数据
            doRequestNewsData(listData, entity, mCallbackResult);
        }));
    }

    /**
     * 请求新闻数据
     */
    public void requestNewsData() {
        requestNewsData( null );
    }

    /**
     * 设置新闻参数
     * @param entity            新闻实体类
     */
    public NewsListRecyclerView setNewsParam(final REFRESH refresh, NewsParamEntity entity) {
        if( entity == null ) return this;
        currentRefresh = refresh;
        mParamEntity = entity;
        return this;
    }

    public NewsListRecyclerView setNewsParam(NewsParamEntity mParamEntity) {
        return setNewsParam(REFRESH.DEFAULT, mParamEntity);
    }

    public NewsParamEntity getNewsParamEntity() {
        return mParamEntity;
    }

    public boolean isDataFirst() {
        return isDataFirst;
    }

    public void setOnRefreshStatusListener(OnRefreshStatusListener mOnRefreshStatusListener) {
        this.mOnRefreshStatusListener = mOnRefreshStatusListener;
    }

    /**
     * 设置新闻数据
     * @param refresh       刷新类型
     * @param dataList      新闻数据
     */
    public void setNewsDataList(long mainLableId, REFRESH refresh,
                                @NonNull List<NewsListEntity> dataList) {
        //不是上拉刷新则清空原数据
        boolean isClear = !refresh.equals(REFRESH.FOOT);
        isDataFirst = true;
        //刷新数据
        notifyDataChange( dataList, isClear );
        LogUtils.d("setNewsDataList", "MainLableId:" + mainLableId);
    }

    public void setNewsDataList(long mainLableId, @NonNull List<NewsListEntity> dataList) {
        LogUtils.d("setNewsDataList",
                "MainLableId:" + mainLableId + " ListSize:" + dataList.size());
        //设置新闻数据
        setNewsDataList(mainLableId, REFRESH.DEFAULT, dataList);
    }

    public int getNewsDataListSize() {
        return mDataList.size();
    }

    /**
     * 刷新状态监听适配器
     */
    public static class OnRefreshStatusAdapter implements
                                                    NewsListRecyclerView.OnRefreshStatusListener {
        @Override
        public void onLoading() { }
        @Override
        public void onResponse(NewsParamEntity paramEntity, List<NewsListEntity> list) { }
        @Override
        public void onFailure() { }
    }

    /**
     * Handler
     */
    private static class ThisHandler extends Handler {
        @Nullable
        private NewsListRecyclerView view;
        ThisHandler(NewsListRecyclerView view) {
            super(Looper.getMainLooper());
            this.view = new WeakReference<>(view).get();
        }
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            if( view == null ) return;
            switch ( msg.what ) {
                case 100://刷新适配器
                    //通知数据发生改变
                    view.mAdapter.notifyDataSetChanged();
                    //显示列表，空数据也会显示
                    if( view.getVisibility() != View.VISIBLE ) {
                        view.mThisHandler.sendEmptyMessage( 500 );
                    }
                    break;
                case 101://结束下拉刷新
                    view.refreshComplete();
                    break;
                case 102://结束上拉加载
                    view.loadMoreComplete();
                    break;
                case 500://显示列表
                    view.setVisibility(View.VISIBLE);
                    break;
                case 501://隐藏列表
                    view.setVisibility(View.INVISIBLE);
                    break;
            }
        }
    }
}
